<?PHP

error_reporting(E_ALL);
// $Id: DpTable.class.php,v 1.1 2009/07/28 17:15:54 dkretz Exp $

/**
 * DpTable Class.
 *
 *
 *  <p>Initialize with a result-set-type array.</p>
 * </p>Use the AddColumn method to accumulate column information.
 *  <p>Sorting. We can either sort in the query, or sort the array.
    Sorting in the query might be quicker, but it means tweaking the
    SQL, which increases coupling, complicates the query (bad), and
    is less general and reusable (bad). So we'll sort in the array.

    This anticipates adding report manipulation to the client,
    as JavaScript becomes more standard (e.g. Ajax, DHTML, etc.)
 */

class DpTable
{
    private $_pager_template = "";
    private $_pager_page_number = "";  // serves as flag for pager
    private $_pager_rows_per_page = "";
    private $_pager_page_min = "";
    private $_pager_page_max = "";
    private $_pager_data_min = "";
    private $_pager_data_max = "";
    private $_pager_increment = "";
    private $_table_caption;
    private $_align;
    private $_sortcol;
    private $_captions   = array() ;
    private $_columns    = array() ;
    private $_rows       = array() ;  // data
    private $_sort_func ;
    private $_sort_A_D   = "A";
    private $_class = null ;
    private $_id = null ;
    private $_rownum;

    /**
     * Constructor.
     *
     */

    function __construct( $pagenumber = null, $rowsperpage = null ) {
        $this->_pager_page_number     = $pagenumber ;
        $this->_pager_rows_per_page   = $rowsperpage ;
    }

    /**
     * SetRows. Argument is resultset-type array (colname => value).
     * 
     */

    public function SetRows($rows) {
        $this->_rows = $rows;
    }

    /**
     * AddColumn.  
     * 
     * 
     */

    public function AddColumn( 
                        $caption,
                        $colname,
                        $template = null,
                        $class = null) {

        $this->_columns[] = new DpTableColumn(
                        $caption, 
                        $colname,
                        $template,
                        $class);
    }

    public function SetClass($class) {
        $this->_class = $class;
    }

    public function SetId($id) {
        $this->_id = $id;
    }

    public function SetPager($pagenum, $rowsperpage = 0, 
                                $min = 0, $max = 0, 
                                $datamax = 0, $template = null) {
        $this->_pager_page_num           = $pagenum;
        $this->_pager_page_rows_per_page = $rowsperpage;
        $this->_pager_page_min           = $min;
        $this->_pager_page_max           = $max;
        $this->_pager_data_max           = $datamax;
        $this->_pager_page_template      = $template;
    }

    public function SetPagerTemplate($tpl) {
        $this->_pager_template = $tpl;
    }

    /**
     * setSort. Arguments: Column name, optional function,
                and optional A or D. (up or down.)
     *
     */

    public function SetSort($sortcolname, 
                            $sortfunc = null, $A_D = "A") {
        $this->_sortcol   = $sortcol ;
        $this->_sortfunct = $sortfunc ;
        $this->_sort_A_D  = $A_D;
    }

    /**
     * echo. Generate the report.
     *
     */

    public function EchoTableNumbered() {
        $this->EchoTable(true) ;
    }

    /**
     * addCaption. Add a superheader above the header row.
     *
     */

    public function AddCaption( $text, $ncol = 1, 
                        $class = null, $template = null ) {
        $this->_captions[] = new DpTableCaption( 
                    $text, $ncol, $class, $template ) ;
    }

    public function GetSort() {
        foreach( $this->_columns as $col ) {
            
        }
    }

    public function RowsPerPage() {
        return $this->_pager_rows_per_page ;
    }

    public function PageNumber() {
        return $this->_pager_page_number ;
    }

    public function EchoTable($isnumbered = false) {
        if(count($this->_columns) == 0) {
            if(! $this->_rows || ! is_array($this->_rows)
                        || count($this->_rows[0]) == 0)
                return ;
            $row = $this->_rows[0];
            foreach($row as $col => $val) {
                if(! is_int($col))
                    $this->AddColumn($col, $col);
            }
        }
        echo "<table "
            . ($this->_id ? " id='{$this->_id}'" : "")
            . " class='{$this->_class} dptable'>\n";

        if( $this->_pager_page_number > 0 || $this->_pager_template)
            $this->_echo_pager() ;
        if(isset($this->_table_caption)) {
            echo "<caption>{$this->_table_caption}</caption>\n";
        }
        echo "<tbody>\n";

        $this->_echo_captions($isnumbered);

        $odd_even = true ;
        $this->_rownum 
            = ( $this->_pager_page_number - 1 ) 
                            * $this->_pager_rows_per_page;
        foreach($this->_rows as $row) {
            $this->_rownum++ ;
            $odd_even = ! $odd_even;
            echo $odd_even
                ? "<tr class='odd'>\n"
                : "<tr class='even'>\n";

            if($isnumbered) {
                echo "<td>{$this->_rownum}</td>\n";
            }

            foreach($this->_columns as $col) {
                $col->EchoCell($row, $this->_rownum);
            }
            echo "</tr>\n";
        }
        if( $this->_pager_page_number > 0 || $this->_pager_template)
            $this->_echo_pager() ;
        echo "</tbody>
            </table>\n";
    }

    /**
     * _echo_captions.
     *
     */

    private function _echo_captions($isnumbered = false) {
        if( count( $this->_captions ) > 0 ) {
            echo "<tr>\n";
            if( $isnumbered ) {
                echo "<th> &nbsp;</th>\n";
            }
            foreach( $this->_captions as $cap ) {
                $cap->EchoCaption() ;
            }
            echo "</tr>\n";
        }
                
            
        echo "<tr>\n";
        if($isnumbered)
            echo "<th> &nbsp;</th>\n";
        foreach($this->_columns as $col) {
            $col->echoCaption($this->_sortcol == $col->colName());
        }
        echo "</tr>\n";
    }

    /**
     * _echo_row($row).
     *
     */

    private function _echo_row($row, $rownum = 0) {
        echo "<tr>\n";
        if($rownum) {
            echo "<td>$rownum</td>\n";
        }
        foreach($this->_columns as $col) {
            $col->EchoCell($row, $rownum);
        }
        echo "</tr>\n";
    }

    private function _echo_pager() {
        if(is_callable($this->_pager_template)) {
            call_user_func($this->_pager_template);
            return;
        }

        if($this->_pager_page_min < $this->_pager_page_max)
            return;
        if(! $this->_pager_template) {
            $this->_pager_template = _("Page %s");
        }

        $str = sprintf($this->_pager_template, 
                       $this->_pager_page_min,
                       $this->_pager_page_max,
                       $this->_pager_data_max);
        
        echo "<tr><td colspan='{$this->ColumnCount()}'>
            $str
            </td></tr>\n";
    }

    public function ColumnCount() {
        return count($this->_columns);
    }

    public function RowCount() {
        return count($this->_rows);
    }
}   // end class DpTable




class DpTableCaption
{
    var $_caption;
    var $_template;
    var $_colcount ;
    var $_align;
    var $_class;

    function __construct( $caption, 
                          $colcount = 1, 
                          $class = null, 
                          $template = null ) {
        $this->_template = $template;
        $this->_caption = $caption ;
        $this->_colcount = $colcount ;
        $this->_set_align( $caption ) ;
        $this->_set_class( $class );
    }

    // 0 = none, 1 = asc, 2 = desc
    private function _set_align($cap) {
        switch($cap[0]) {
            default :
                $this->_align = "" ;
                $this->_caption = $cap ;
                return ;
            case '<' :
                $this->_align = " style='text-align: left'";
                break ;
            case '>' :
                $this->_align = " style='text-align: right'";
                break ;
            case '^' :
                $this->_align = " style='text-align: center'";
                break ;
        }
        $this->_caption = mb_substr( $cap, 1 ) ;
    }

    private function _set_class( $class ) {
        $this->_class = empty($class)
            ? ""
            : "class='$class'";
    }

    public function EchoCaption() {
        echo "<th$this->_align $this->_class" ;
        if( $this->_colcount > 1 ) {
            echo " colspan='{$this->_colcount}'";
        }
        echo ">";

        if(! $this->_template) {
            $str = $this->_caption;
        }
        else if(is_callable($template)) {
            $str = call_user_func($template);
        }
        
        echo "{$str}</th>\n";
    }
}

///////////////////////////////////////////////////////////////////

/**
     * DpTableColumn class.
     */

///////////////////////////////////////////////////////////////////

class DpTableColumn
{
    private $_caption;
    private $_colname;
    private $_template;
    private $_sortfunc;
    private $_class = null;
    private $_align;

    /**
    Initializer.

    caption is text column heading.
    colname is the name of the field in the resultset row.
    template is one of:
        a. empty - the cell value is echoed.
        b. an "sprintf" format string, 
           optionally including "%s" for the cell value.
        c. if colname is empty, a function to echo any string 
           derivable from the $row. Notice a colname for the
           column is redundant.
        class is the name of the css class to use.
        Public.
     */

    function __construct(
                $caption, 
                $colname, 
                $template = null, 
                $class = null,
                $sortfunc = null) {
        $this->_colname = $colname;
        $this->_template = $template;
        $this->_set_align( $caption ) ;
        $this->_set_class( $class );
        $this->_sort_func = $sortfunc;
    }

    public function CycleSort() {
        if( $this->_sort == 2 )
            $this->_sort = 0 ;
        else
            $this->sort++ ;
    }

    private function _set_align($cap) {
        if(empty($cap[0]))
            return;
        switch($cap[0]) {
            default :
                $this->_align = "" ;
                $this->_caption = $cap ;
                return ;
            case '<' :
                $this->_align = " style='text-align: left'";
                break ;
            case '>' :
                $this->_align = " style='text-align: right'";
                break ;
            case '^' :
                $this->_align = " style='text-align: center'";
                break ;
        }
        $this->_caption = mb_substr( $cap, 1 ) ;
    }

    private function _set_class( $class ) {
        $this->_class = empty($class)
            ? ""
            : "class='$class'";
    }

    public function EchoCaption() {
        $str = $this->_caption;
        if($this->_sortfunc) {
            $str = "<a onclick={this->_sortfunc}()>$str</a>\n";
        }
        $str = "<th{$this->_align} {$this->_class}>$str</th>\n";
        echo $str;
    }

    public function EchoCell($row, $rownum) {
        $cname = $this->_colname;
        // if($cname == "_rownum") {
            // $str = $rownum;
            // $cname = $this->_rownum;
        // }
        $template = $this->_template;

        if(! isset($template)) {
            if(isset($cname)) {
                if(isset($row[$cname])) {
                    $str = $row[$cname];
                }
                else {
                    $str = $cname;
                }
            }
            else {
                $str = "";
            }
        }
        else if(is_callable($template)) {
            if(isset($cname)) {
                if(isset($row[$cname])) {
                    $str = call_user_func($template, 
                                        $row[$cname], $row);
                }
                else {
                    if(empty($cname))
                        $cname = "null";
                    $str = call_user_func($template, $cname, $row);
                }
            }
            else {
                    $str = call_user_func($template, $row);
            }
        }
        else {
        // template but not a function
            if(isset($cname)) {
                if(isset($row[$cname])) {
                    $str = sprintf($template, $row[$cname]);
                }
                else {
                    $str = sprintf($template, $cname);
                }
            }
            else {
                $str = sprintf($template);
            }
        }
        
        echo "<td $this->_class $this->_align>$str</td>\n";
    }

    public function ColName() {
        return $this->_colname;
    }
} // end DpTableColumn

?>
